package com.gitee.aurora.utils;

import com.gitee.aurora.comm.AuroraJdbcTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 分批处理工具类
 *
 * @author chenke
 * @version 1.0
 * @date 2020-11-17 14:48
 */
public class BatchUtil {

    @Autowired
    private static AuroraJdbcTemplate auroraJdbcTemplate;

    public static <T> void batch(List<T> list, int pageSize, BatchCallback callback) {

        int listCount = list.size();

        if (listCount <= pageSize) {
            callback.call(list);
            return;
        }

        // 总共多少批
        int batchCount = listCount / pageSize;
        // 剩余多少
        int remainder = listCount % pageSize;

        for (int i = 0; i < batchCount; i++) {
            List<T> temp = list.subList(i * pageSize, (i + 1) * pageSize);
            callback.call(temp);
        }

        if (remainder > 0) {
            List<T> temp = list.subList(batchCount * pageSize, listCount);
            callback.call(temp);
        }

    }

    /**
     * 分批方法
     *
     * @param count    总数
     * @param pageSize 每批大小
     * @author chenke
     * @date 2020-11-17 14:50
     */
    public static void batchPage(int count, int pageSize, BatchPageCallback callback) {

        if (count == 0) {
            return;
        }

        // 取整
        int trunc = count / pageSize;
        // 取余
        int remainder = count % pageSize;

        // 只有一批数据
        if (trunc == 0) {
            callback.call(0, remainder);
            return;
        }

        // 每批循环调用
        for (int i = 0; i < trunc; i++) {
            callback.call(i * pageSize, pageSize);
        }

        if (remainder != 0) {
            callback.call(trunc * pageSize, remainder);
        }

    }

    /**
     * 批量保存数据
     *
     * @param dataList  数据
     * @param sjzxTable 数据中心表
     * @param database  数据中心库
     * @return void
     * @throws
     * @author chenke
     * @date 2021-07-22 13:10
     */
    public static void batchSaveData(List<Object> dataList, String sjzxTable, String database) {
        for (Object obj:dataList) {
            try {
                Field gsxj = obj.getClass().getDeclaredField("GXSJ");
                gsxj.setAccessible(true);
                gsxj.set(obj,new Date());
            } catch (NoSuchFieldException | IllegalAccessException e) {
            }
        }

        // 拼接SQL语句,格式如下
        // INSERT INTO TABLE (a,c) VALUES (1,3),(1,7) ON DUPLICATE KEY UPDATE a=VALUES(a),c=VALUES(c);
        Field[] fields = dataList.get(0).getClass().getDeclaredFields();
        int length = fields.length;

        // 所有插入字段
        StringBuilder fieldAll = new StringBuilder();
        fieldAll.append(" (");
        // 所有更新字段
        StringBuilder updateField = new StringBuilder();
        int fieldCount = 1;
        for (int i = 0; i < length; i++) {
            Field field = fields[i];
            // 需要包含Column注解,即表中字段,才做处理
            if (!field.isAnnotationPresent(Column.class)) {
                continue;
            }
            String columnName = field.getAnnotation(Column.class).name();
            if (fieldCount == 1) {
                fieldAll.append(columnName);
                updateField.append(columnName + "=VALUES(" + columnName + ")");
            } else {
                fieldAll.append("," + columnName);
                updateField.append("," + columnName + "=VALUES(" + columnName + ")");
            }
            fieldCount++;
        }
        fieldAll.append(") ");

        // 循环拼接中间字段值
        StringBuilder values = new StringBuilder();
        // 问号替换值
        List<Object> paramList = new ArrayList<>();
        int rowCount = dataList.size();
        for (int i = 0; i < rowCount; i++) {

            if (i > 0) {
                // 每行数据之间逗号
                values.append(",");
            }

            // 每行数据值
            values.append("(");

            fieldCount = 1;
            for (int j = 0; j < length; j++) {
                Field field = fields[j];
                // 需要包含Column注解,即表中字段,才做处理
                if (!field.isAnnotationPresent(Column.class)) {
                    continue;
                }
                if (fieldCount == 1) {
                    values.append("?");
                } else {
                    values.append(",?");
                }

                paramList.add(getFieldValue(dataList.get(i), field));

                fieldCount++;
            }

            values.append(")");

        }

        StringBuilder sql = new StringBuilder();
        sql.append("INSERT INTO ");
        sql.append(sjzxTable);
        sql.append(fieldAll);
        sql.append(" VALUES ");
        sql.append(values);
        sql.append(" ON DUPLICATE KEY UPDATE ");
        sql.append(updateField);
        auroraJdbcTemplate.execute(sql.toString(), paramList);
    }

    /**
     * 获取PO对象属性字段值
     *
     * @param data  PO对象
     * @param field 字段对象
     * @return java.lang.Object
     * @author chenke
     * @date 2021-01-23 19:57
     */
    private static Object getFieldValue(Object data, Field field) {
        try {
            field.setAccessible(true);
            Object value = field.get(data);

            if (value == null) {
                return null;
            }

            //更新时间为当前时间
            String fieldName = field.getName();
            if (StringUtils.isNotEmpty(fieldName) && "gxsj".equals(fieldName)) {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            }

            String type = field.getType().getName();
            if (type.equals("java.util.Date")) {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value);
            }

            if (type.equals("java.lang.String")) {
                if ("".equals(value)) {
                    return null;
                }
            }
            return value;
        } catch (Exception e) {
            return null;
        }
    }

}
